package gugga.collections.checkList
{
	import flash.events.EventDispatcher;
	
	import gugga.collections.IIterable;
	import gugga.collections.IIterator;
	import gugga.debug.Assertion;
	
	[Event(name="completed", type="CheckListEvent")]
	
	/**
	 * <code>CheckList</code> is a container for items that should be checked.
	 * <p> 
	 * To register new item in the <code>CheckList</code> use the <code>add()</code> 
	 * method. 
	 * <p>
	 * To check existing items in the <code>CheckList</code> use the 
	 * <code>check()</code> method.
	 * <p>
	 * To uncheck all checked items in the <code>CheckList</code> use the 
	 * <code>reset()</code> method.
	 * <p>
	 * To unregister existing item in the <code>CheckList</code> use the 
	 * <code>remove()</code> method.
	 * <p>
	 * <code>isCompleted()</code> method will return <code>true</code> only if all 
	 * registered items in the <code>CheckList</code> are checked.
	 * <p>
	 * <code>isObjectChecked(aObject:Object)</code> method will return 
	 * <code>true</code> only if the specified <code>Object</code> is a registered 
	 * item in the <code>CheckList</code> and it is checked.
	 * <p>
	 * <code>isObjectRegistered(aObject:Object)</code> method will return 
	 * <code>true</code> only if the specified <code>Object</code> is a registered 
	 * item in the <code>CheckList</code>.
	 * <p>
	 * To get the <code>ArrayList</code> of all registered items in the 
	 * <code>CheckList</code> use the <code>RegisteredObjects</code> property.
	 * <p>
	 * To get the <code>ArrayList</code> of all checked items in the 
	 * <code>CheckList</code> use the <code>CheckedObjects</code> property.
	 * <p>
	 * To get the <code>ArrayList</code> of all unchecked items in the 
	 * <code>CheckList</code> use the <code>UncheckedObjects</code> property.
	 */
	public class CheckList extends EventDispatcher implements IIterable
	{
		private var mRegisteredObjects : Array;
		private var mCheckedObjects : Array;
		
		public function get RegisteredObjects() : Array
		{
			return mRegisteredObjects.slice();
		}
		
		public function get CheckedObjects() : Array
		{
			return mCheckedObjects.slice();
		}
		
		public function get UncheckedObjects() : Array
		{
			var result : Array = new Array();
			for (var i : int = 0; i < mRegisteredObjects.length; i++)
			{
				var item : Object = mRegisteredObjects[i];
				if(!isObjectChecked(item))
				{
					result.push(item);
				}
			}
			
			return result;
		}
		
		public function CheckList()
		{
			mRegisteredObjects = new Array();
			mCheckedObjects = new Array();
		}
		
		public function add(aObject:Object) : void
		{
			Assertion.failIfReturnsTrue(
				this, isObjectRegistered, [aObject], 
				"Object already added", this, arguments);
			
			mRegisteredObjects.push(aObject);
		}
		
		public function remove(aObject : Object) : void
		{
			var indexOfObject : int = mRegisteredObjects.indexOf(aObject);
			if(indexOfObject != -1)
			{
				mRegisteredObjects.splice(indexOfObject, 1);
			}
			
			indexOfObject = mCheckedObjects.indexOf(aObject);
			if(indexOfObject != -1)
			{
				mCheckedObjects.splice(indexOfObject, 1);
			}
		}
			
		public function check(aObject:Object) : void
		{
			Assertion.failIfReturnsFalse(
				this, isObjectRegistered, [aObject], 
				"Trying to check unregistered object", this, arguments);
			
			if(!isObjectChecked(aObject))
			{
				mCheckedObjects.push(aObject);	
				
				if(isCompleted())
				{
					dispatchEvent(new CheckListEvent(CheckListEvent.COMPLETED));
				}
			}
		}
		
		public function reset() : void
		{
			mCheckedObjects = new Array();
		}
		
		public function	isObjectRegistered(aObject:Object):Boolean
		{	
			var objectIndex : int = mRegisteredObjects.indexOf(aObject, 0);
			var isRegistered : Boolean = false;
			if(objectIndex != -1)
			{
				isRegistered = true;
			}
			
			return isRegistered;
		}
		
		public function	isObjectChecked(aObject:Object):Boolean
		{	
			var objectIndex : int = mCheckedObjects.indexOf(aObject, 0);
			var isChecked : Boolean = false;
			if(objectIndex != -1)
			{
				isChecked = true;
			}
			
			return isChecked;
		}
			
		public function isCompleted():Boolean
		{
			var result : Boolean = mCheckedObjects.length == mRegisteredObjects.length;
			return result;
		}
		
		public function getIterator() : IIterator
		{
			Assertion.warning("Method is not implemendted", this, []);
			return null;
		}		
	}
}